import { CydonElement, define } from 'cydon'
import { API, Post } from '../api'
import { getLink, getPost, updateImg } from '../models/post'
import { getUser, getCollaborator, getUserNames } from '../models/user'
import { success } from '@cydon/ui/Message'
import { CAsync, CustomTabEvent } from '@cydon/ui/components'
import '@cydon/ui/components/CAsync'
import { render, sizeNum, submitOnEnter } from '../utils/helper'
import { parseURL } from '../utils/router'
import { error, onHashChange } from '../utils'
import { getHotTags } from '../models/tag'
import { PostThumb } from './PostThumb'
import { postview } from './TagItem'

let infoLoaded: () => void,
	imgLoaded: () => void
let hotTags: string[]

const posts = document.getElementById('posts')!

@define('side-bar')
export class SideBar extends CydonElement {
	//#region 属性
	/** 当前查看的帖子 */
	_post = <Post>{ id: 0 }
	get post() {
		return this._post
	}

	tagTitle = '标签'
	/** 标签列表 */
	tags: string[] = []
	/** 待添加标签，空格分隔 */
	tagToAdd = ''
	/** 变更请求的标题 */
	reason = ''
	/** 变更请求的描述 */
	desc = ''
	/** 备注 */
	note = ''
	/** 锁定时长 */
	duration = 24 * 60 * 60
	/** 是否显示序号 */
	showOrder = false
	// /** 无限滚动 */
	//infiniteScroll = false

	infoLoaded = new Promise<void>(r => infoLoaded = r)
	imgLoaded = new Promise<void>(r => imgLoaded = r)

	img!: HTMLImageElement
	infos!: NodeListOf<CAsync>
	//#endregion

	//#region 计算属性
	get pid() { return this.post.id }
	set pid(id) {
		this.post.id = id
	}

	/** 是否全选 */
	get selectAll() {
		return posts.children.length > 0 &&
			[...posts.children].every(p => p.classList.contains('selected'))
	}
	set selectAll(value) {
		for (const p of posts.children)
			p.classList.toggle('selected', value)
	}

	get BLAKE3() { return render('hash', this.post.hash) }
	get created_at() { return render('created_at', this.post.created_at) }
	get updated_at() { return render('updated_at', this.post.updated_at) }

	/** 获取帖子大小 */
	async getSize() {
		await this.infoLoaded
		if (!this.post.hash)
			return ''
		const urls = await API.linksOf(this.post.hash)
		for (const url of urls) {
			const link = await getLink(url)
			if (link?.size)
				return sizeNum(link.size)
		}
		return ''
	}

	/** 获取创建者名称 */
	async getCreator() {
		await this.infoLoaded
		const user = await getUser(this.post.creator)
		return user?.name || ''
	}

	/** 获取协作者 */
	async getCollaborators() {
		await this.infoLoaded
		const [, ...c] = await getCollaborator(this.post.creator)
		return (await getUserNames(c.map(c => c.creator))).join(' ')
	}

	/** 分辨率 */
	async getResolution() {
		await this.imgLoaded
		const img = this.img
		let res = img.naturalWidth + 'x' + img.naturalHeight
		if (img.width != img.naturalWidth || img.height != img.naturalHeight) {
			res += ` (显示 ${img.width}x${img.height})`
		}
		return res
	}
	//#endregion

	async connectedCallback() {
		// TODO: 重构
		await customElements.whenDefined('c-async')
		super.connectedCallback()
		this.infos = this.querySelectorAll('c-async')
		this.img = <HTMLImageElement>document.getElementById('post')
		onHashChange(async hash => {
			const params = parseURL(hash)
			const pid = +params! || 0
			this.data.pid = pid
			let expr
			if (pid) {
				const post = <Post>await getPost(pid)
				post.id = pid
				this.view(post)
			} else {
				this.img.hidden = true
				if (typeof params == 'object') {
					expr = params?.search
				}
			}
			this.getTags(expr)
		})
	}

	/** 重置信息 */
	resetInfo() {
		this.infoLoaded = new Promise<void>(r => infoLoaded = r)
		this.imgLoaded = new Promise<void>(r => imgLoaded = r)
		for (const el of this.infos) {
			el.status = 'pending'
		}
	}

	/** 提交 */
	async submit(e: SubmitEvent) {
		e.preventDefault()
		const btn = e.submitter as HTMLButtonElement
		btn.disabled = true
		try {
			await (<any>this)[btn.dataset.action!](btn)
		} finally {
			btn.disabled = false
		}
	}

	/** 添加标签 */
	addTag(e: SubmitEvent) {
		e.preventDefault()
		const tag = new FormData(e.target as HTMLFormElement).get('tag') as string
		if (tag) {
			this.tags.push(...tag.split(' '))
			this.tagToAdd = ''
		}
	}

	/** 清空标签 */
	clearTag() {
		this.tags = []
	}

	/** 重置标签 */
	resetTag() {
		this.tags = this.post.tags?.split(' ') || []
	}

	/** 提交更改 */
	async submitTag(btn: HTMLButtonElement) {
		const set = new Set<string>()
		for (const tag of this.tags)
			if (tag)
				set.add(tag)
		for (const tag of this.tagToAdd.split(/s+/))
			if (tag)
				set.add(tag);
		return API.tag(this.pid, [...set].sort().join(' '), this.reason, this.desc)
			.then(([id]) => {
				success('提交成功，变更请求ID：' + id)
				btn.form?.reset()
			}, error)
	}

	/** 获取标签列表 */
	async getTags(expr?: string) {
		this.data.tagTitle = (this.pid ? '' : expr ? '相关' : '热门') + '标签'
		if (this.pid) {
			const tags = (await getPost(this.pid))?.tags
			if (tags)
				this.tags = tags.split(' ')
		} else if (expr) {
			// 获取相关标签
			const tags = await API.getRelatedTags(expr.replace(/[*(|)]/g, ' '), 20)
			this.tags = tags
		} else {
			// 获取热门标签
			hotTags ||= (await getHotTags(20)).map(t => t.name)
			this.tags = hotTags
		}
	}

	//#region 事件
	/** 反选 */
	selectInv(e: Event) {
		e.preventDefault()
		for (const p of posts.children)
			p.classList.toggle('selected')
	}

	/** 查看帖子 */
	async view(post: Post) {
		this.data._post = post
		this.data.tags = post.tags?.split(' ') || []
		if (post.id) {
			infoLoaded()
			location.hash = '#' + post.id
		}
		const oldPid = this._post.id
		if (oldPid != post.id) {
			this.resetInfo()
		}
		this.img.addEventListener('load', imgLoaded, { once: true })
		await updateImg(this.img, post, true)
		this.img.hidden = false
	}

	/** 锁定选中图片 */
	lock(e: Event) {
		e.preventDefault()
		for (const p of posts.children)
			if (p.classList.contains('selected'))
				API.lockPost((<PostThumb>p).pid, this.duration, this.note).then(
					() => success('操作成功'), error)
	}

	/** 切换编辑模式 */
	changeTab(e: CustomTabEvent) {
		const edit = !e.detail.relatedTarget.nextSibling
		this.classList.toggle('edit', edit)
	}

	/** 清除无标签图片 */
	clearUntagged(e: Event) {
		e.preventDefault()
		API.clearUntagged().then(() => {
			success('操作成功')
			location.reload()
		}, error)
	}

	/** 重建索引 */
	rebuild(e: Event) {
		e.preventDefault()
		API.rebuildIndex().then(() => success('操作成功'), error)
	}

	/** 更新标签的使用数 */
	updateTagCount(e: Event) {
		e.preventDefault()
		API.updateTagCount().then(() => {
			success('操作成功')
			location.reload()
		}, error)
	}

	/** 返回 */
	back(e: Event) {
		e.preventDefault()
		location.hash = ''
		postview.updateValue('pid')
	}

	/** 删除 */
	async del(btn: HTMLButtonElement) {
		if (this.post.tags) {
			error('请先清空标签并提交更改')
		}
		return API.delPost(this.pid).then(([n]) => {
			success('删除成功：共删除' + n + '个链接')
			btn.form?.reset()
			location.hash = ''
		}, error)
	}

	/** 回车提交 */
	keyup = submitOnEnter
	//#endregion
}

declare global {
	interface HTMLElementTagNameMap {
		'side-bar': SideBar
	}
}
